#pragma once

#include <string>
#include "string.hpp"
#include "string_view.hpp"

namespace zuck
{
	template<typename Char>
	unsigned int __SDBM_hash(Char const* const str)
	{
		unsigned int hash = 0;
		for (; *str;) {
			hash = *(str++) + (hash << 6) + (hash << 16) - hash;
		}
		return (hash & 0x7fffffff);
	}

	template<typename Char>
	unsigned int __ELF_hash(Char const* const str)
	{
		unsigned int hash = 0;
		unsigned int x    = 0;
		for (; *str;) {
			hash = (hash << 4) + *(str++);
			if ((x = hash & 0xf0000000l)) {
				hash ^= (x >> 24);
				hash &= ~x;
			}
		}
		return (hash & 0x7fffffff);
	}

	template<typename Char>
	unsigned int __DEK_hash(Char const* const str, unsigned int len)
	{
		unsigned int hash = len;
		unsigned int i    = 0;
		for (i = 0; i < len; ++str, ++i) {
			hash = ((hash << 5) ^ (hash >> 27)) ^ (*str);
		}
		return (hash & 0x7fffffff);
	}

	template<typename Char>
	unsigned int __AP_hash(Char const* str)
	{
		unsigned int hash = 0;
		unsigned int i;
		for (i = 0; *str; ++i) {
			if (!(i & 1)) {
				hash ^= ((hash << 7) ^ (*str++) ^ (hash >> 3));
			}
			else {
				hash ^= (~((hash << 11) ^ (*str++) ^ (hash >> 5)));
			}
		}
		return (hash & 0x7fffffff);
	}

	template<typename T>
	class hash_func;

	template<>
	class hash_func<std::string> {
	public:
		[[nodiscard]] inline size_t operator()(std::string& str)const
		{
			return __AP_hash(str.c_str());
		}
	};

	template<>
	class hash_func<char const*> {
	public:
		[[nodiscard]] inline size_t operator()(char const* const str)const
		{
			return __AP_hash(str);
		}
	};

	template<>
	class hash_func<wchar_t const*> {
	public:
		inline size_t operator()(wchar_t const* const str)const
		{
			return __AP_hash(str);
		}
	};

	template<>
	class hash_func<char16_t const*> {
	public:
		inline size_t operator()(char16_t const* const str)const
		{
			return __AP_hash(str);
		}
	};

	template<>
	class hash_func<char32_t const*> {
	public:
		inline size_t operator()(char32_t const* const str)const
		{
			return __AP_hash(str);
		}
	};

	template<>
	class hash_func<char> {
	public:
		inline size_t operator()(char key)const
		{
			return key;
		}
	};

	template<>
	class hash_func<uchar> {
	public:
		inline size_t operator()(uchar key)const
		{
			return key;
		}
	};

	template<>
	class hash_func<int> {
	public:
		inline size_t operator()(int key)const
		{
			return key;
		}
	};

	template<>
	class hash_func<unsigned int> {
	public:
		inline size_t operator()(unsigned int key)const
		{
			return key;
		}
	};

	template<>
	class hash_func<long> {
	public:
		inline size_t operator()(long key)const
		{
			return key;
		}
	};

	template<>
	class hash_func<unsigned long> {
	public:
		inline size_t operator()(unsigned long key)const
		{
			return key;
		}
	};

	template<>
	class hash_func<long long> {
	public:
		inline size_t operator()(long long key)const
		{
			return key;
		}
	};

	template<>
	class hash_func<unsigned long long> {
	public:
		inline size_t operator()(unsigned long long key)const
		{
			return key;
		}
	};
}

